/*
 ============================================================================
 Name        : threadDemo.c
 Author      : 
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
#include <syslog.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stddef.h>                     /* For definition of offsetof() */
#include <stdarg.h>                     /* For definition of offsetof() */
#include <limits.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>  /* Type definitions used by many programs */
#include <stdio.h>      /* Standard I/O functions */
#include <stdlib.h>     /* Prototypes of commonly used library functions,
                           plus EXIT_SUCCESS and EXIT_FAILURE constants */
#include <unistd.h>     /* Prototypes for many system calls */
#include <errno.h>      /* Declares errno and defines error constants */
#include <string.h>     /* Commonly used string-handling functions */
#include <sys/param.h>
#include <pthread.h>
#include <semaphore.h>

extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg));


typedef enum { FALSE, TRUE } Boolean;
/*
使用多线程的理由之一是和进程相比，它是一种非常"节俭"的多任务操作方式。我们知道，在Linux 系统下，
启动一个新的进程必须分配给它独立的地址空间，建立众多的数据表来维护它的代码段、堆栈段和数据段，
这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程，它们彼此之间使用相同的地址空间，
共享大部分数据，启动一个线程所花费的空间远远小于启动一个进程所花费的空间，而且，线程间彼此切
换所需的时间也远远小于进程间切换所需要的时间。据统计，总的说来，一个进程的开销大约是一个线程
开销的30 倍左右，当然，在具体的系统上，这个数据可能会有较大的区别
 */
struct menber
{
	int a;
	char *s;
};
void cleanup(void *arg)
{
	printf("cleanup arg:%s\n",arg);
}
void *thread_one(void *arg)
{
	pid_t pid;
	pthread_t tid;
	pid=getpid();
	tid=pthread_self();
	struct menber *parameter=(struct menber *)arg;
	pthread_cleanup_push(cleanup,(void*)parameter->s); //atexit();
	printf("thread_one: the pid is %u ,the thread is %u \n",pid,tid);
	printf("a:%d s:%s\n",parameter->a,parameter->s);
	pthread_cleanup_pop(1); //pthread_cleanup_pop(0);//atexit();
	pthread_exit((void *)parameter->a);
}
void *thread_two(void *arg)
{
	pid_t pid;
	pthread_t tid;
	pid=getpid();
	tid=pthread_self();
	printf("thread_two: the pid is %u ,the thread is %u \n",pid,tid);
	return (void*)8;
}
void pthreadParamter()
{
	int err,stat_val;;
	pid_t pid,childPid;
	pthread_t tid_one,tid_two;
	pid=getpid();
	tid_one=pthread_self();
	void *retValue_one,*retValue_two;
	struct menber parameter;
	parameter.a=123456;
	parameter.s="suiyuan";

	if((childPid=fork())==-1)
	{
		perror("fork");
		exit(EXIT_FAILURE);
	}
	else if(childPid==0)
	{
		err=pthread_create(&tid_one,NULL,thread_one,(void *)¶meter);
		if(err!=0)
		{
			printf("error message is:%s\n",strerror(err));
			exit(1);
		}
		pthread_join(tid_one,&retValue_one);
		printf("pthread_join,thread_one return value:%d\n",(int)retValue_one);
	}
	else
	{
		pthread_create(&tid_two,NULL,(void *)thread_two,NULL);
		if(err!=0)
		{
			printf("error message is:%s\n",strerror(err));
			exit(1);
		}
		pthread_join(tid_two,&retValue_two);
		printf("pthread_join,thread_two return value:%d\n",(int)retValue_two);
		printf("pid:%d getpid:%d\n",pid,getpid());
		waitpid(childPid, &stat_val, 0);
		if (WIFEXITED(stat_val))
		{
			printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
		}
		else if (WIFSIGNALED(stat_val))
		{
			printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
		}
	}
	printf("main thread:the pid is %u ,the thread is %u \n",pid,tid_one);
}
/*
 如果进程中任何一个线程中调用exit，_Exit,或者是_exit，那么整个进程就会终止，
与此类似，如果信号的默认的动作是终止进程，那么，把该信号发送到线程会终止进程。
线程的正常退出的方式：
(1) 线程只是从启动例程中返回，返回值是线程中的退出码
(2) 线程可以被另一个进程进行终止
(3) 线程自己调用pthread_exit 函数
 */
//************************************************************************************************
#if 1
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#endif
#if 1
static int avail = 0;
static void *pthread_mutex_lock_Func(void *arg)
{

    int cnt = *((int *) arg);
    int s, j;
    printf("pthread_mutex_lock_Func:arg:%d\n",cnt);
    sleep(1);
    for (j = 0; j < cnt; j++) {
        sleep(2);
        /* Code to produce a unit omitted */
        s = pthread_mutex_lock(&mtx);
        if (s != 0)
            perror("pthread_mutex_lock");
        avail++;        /* Let consumer know another unit is available */
        s = pthread_mutex_unlock(&mtx);
        if (s != 0)
            perror("pthread_mutex_unlock");
#if 1
        s = pthread_cond_signal(&cond);         /* Wake sleeping consumer */
        if (s != 0)
            perror("pthread_cond_signal");
#endif
    }
    return NULL;
}
void pthread_mutex_lock_test(int num)
{
    pthread_t tid;
    int s;
    int totRequired;            /* Total number of units that all threads will produce */
    int numConsumed;            /* Total units so far consumed */
    Boolean done;
    time_t t;
    t = time(NULL);
    /* Create all threads */
    {
        totRequired = num;
        printf("totRequired:%d\n",totRequired);
        s = pthread_create(&tid, NULL, pthread_mutex_lock_Func, (void *)&totRequired);
        if (s != 0)
        	perror("pthread_create");
    }
    /* Use a polling loop to check for available units */
    numConsumed = 0;
    done = FALSE;
    for (;;) {
        s = pthread_mutex_lock(&mtx);
        if (s != 0)
        {
            perror("pthread_mutex_lock");
        }
    //    while (avail == 0)
        {            /* Wait for something to consume */
            s = pthread_cond_wait(&cond, &mtx);
            if (s != 0)
            	perror("pthread_cond_wait");
        }
 //       while (avail > 0)
        {             /* Consume all available units */
            /* Do something with produced unit */
        	numConsumed ++;
        	printf("condition is ture;T=%ld: avail=%d numConsumed=%d\n", (long) (time(NULL) - t),avail,numConsumed);
            avail--;
            done = numConsumed >= totRequired;
        }
        s = pthread_mutex_unlock(&mtx);
        if (s != 0)
        {
        	perror("pthread_mutex_unlock");
        }
        if (done)
        {
            break;
        }
        /* Perhaps do other work here that does not require mutex lock */
    }
    exit(EXIT_SUCCESS);
}
#endif
//***************************************condition example***********************************************
#if 1
/*
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
*/
static int glob = 0;
static void cleanupHandler(void *arg)    /* Free memory pointed to by 'arg' and unlock mutex */
{
    int s;
    printf("cleanup: freeing block at %p\n", arg);
    free(arg);

    printf("cleanup: unlocking mutex\n");
    s = pthread_mutex_unlock(&mtx);
    if (s != 0)
    	perror("pthread_mutex_unlock");
}

static void *mutex_conditionFunc(void *arg)
{
    int s;
    void *buf = NULL;                   /* Buffer allocated by thread */

    buf = malloc(0x10000);              /* Not a cancellation point */
    printf("thread:  allocated memory at %p\n", buf);
    s = pthread_mutex_lock(&mtx);       /* Not a cancellation point */
    if (s != 0)
    {
    	perror("pthread_mutex_lock");
    }
    pthread_cleanup_push(cleanupHandler, buf);
  //  while (glob == 0)
    {
    	printf("pthread_cond_wait become to ture\n");
        s = pthread_cond_wait(&cond, &mtx);     /* A cancellation point */
        if (s != 0)
        {
        	perror("pthread_cond_wait");
        }
    }
    printf("thread:  condition wait loop completed\n");
    pthread_cleanup_pop(1);             /* Executes cleanup handler */
    return NULL;
}
void mutex_condition_test(int argc)
{
    pthread_t thr;
    void *res;
    int s;
    s = pthread_create(&thr, NULL, mutex_conditionFunc, NULL);
    if (s != 0)
    {
    	perror("pthread_create");
    }
    printf("main: sleep 5s\n");
    sleep(5);                   /* Give thread a chance to get started */
    if (argc == 1)
    {            /* Cancel thread */
        printf("main:    about to cancel thread\n");
        s = pthread_cancel(thr);
        if (s != 0)
        {
        	perror("pthread_cancel");
        }
    } else
    {                    /* Signal condition variable */
        printf("main:    about to signal condition variable\n");
        glob = 1;
        s = pthread_cond_signal(&cond);
        if (s != 0)
        {
        	perror("pthread_cond_signal");
        }
    }

    s = pthread_join(thr, &res);
    if (s != 0)
    	perror("pthread_join");
    if (res == PTHREAD_CANCELED)
        printf("main:    thread was canceled\n");
    else
        printf("main:    thread terminated normally\n");

    exit(EXIT_SUCCESS);
}
#endif


static int globCount = 0;
static sem_t postsem;

static void * threadPostSemaphoresFunc(void *arg)                  /* Loop 'arg' times incrementing 'glob' */
{
    int loops = *((int *) arg);
    int loc, j;
    for (j = 0; j < loops; j++) {
        if (sem_wait(&postsem) == -1)
            perror("sem_wait");
        loc = globCount;
        loc++;
        globCount = loc;
        printf("threadPostSemaphoresFunc:loops %d globCount %d\n",loops, globCount);
        sleep(1);
        if (sem_post(&postsem) == -1)
            perror("sem_post");
    }
    return NULL;
}
void threadAndPostSemaphoresTest(int loops)
{
    pthread_t t1, t2;
    int s,loops1=loops+1;

    /* Initialize a semaphore with the value 1 */
    if (sem_init(&postsem, 0, 1) == -1)
        perror("sem_init");

    /* Create two threads that increment 'glob' */

    s = pthread_create(&t1, NULL, threadPostSemaphoresFunc, &loops1);
    if (s != 0)
    	perror("pthread_create");
    s = pthread_create(&t2, NULL, threadPostSemaphoresFunc, &loops);
    if (s != 0)
    	perror("pthread_create");

    /* Wait for threads to terminate */
    s = pthread_join(t1, NULL);
    if (s != 0)
    	perror("pthread_join");
    s = pthread_join(t2, NULL);
    if (s != 0)
    	perror("pthread_join");

    printf("globCount = %d\n", globCount);
    exit(EXIT_SUCCESS);

}
usageError(const char *progName, const char *msg)
{
    if (msg != NULL)
    {
        fprintf(stderr, "%s", msg);
    }
    fprintf(stderr, "Usage: %s [options] parameter\n", progName);
    fprintf(stderr, "Usage: %s [tm:c:p:] parameter\n", progName);
    fprintf(stderr, "Usage: %s  -t ;to execute:pthreadParamter()\n", progName);
    fprintf(stderr, "Usage: %s  -m parameter;to execute:pthread_mutex_lock_test()\n", progName);
    fprintf(stderr, "Usage: %s  -c [parameter];to execute:mutex_condition_test()\n", progName);
    fprintf(stderr, "Usage: %s  -p parameter;to execute:threadAndPostSemaphoresTest()\n", progName);
    fprintf(stderr, "Usage: %s  -h ;to execute:help\n", progName);

    exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
	int opt;
	if(argc==1)
	{
		perror("");
		usageError(argv[0], NULL);
	}
	while ((opt = getopt(argc, argv, "tm:c:k:p:")) != -1) {
		switch (opt) {
		case 't':
			pthreadParamter();
			break;
		case 'm':
			if(optarg!=NULL)
			{
				printf("optopt:%c   :%d\n",optopt,atoi(optarg));
				pthread_mutex_lock_test(atoi(optarg));
			}
			else
			{
				usageError(argv[0], NULL);
			}
			break;
		case 'c':
			if(optarg!=NULL)
			{
				printf("optopt:%c   :%d\n",optopt,atoi(optarg));
				mutex_condition_test(atoi(optarg));
			}
			else
			{
				usageError(argv[0], NULL);
			}
			break;
		case 'p':
			if(optarg!=NULL)
			{
				printf("optopt:%c   :%d\n",optopt,atoi(optarg));
				threadAndPostSemaphoresTest(atoi(optarg));
			}
			else
			{
				usageError(argv[0], NULL);
			}
			break;
		default:

			usageError(argv[0], NULL);
		}
	}
	return EXIT_SUCCESS;
}

